package com.yc.xunlei;

import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class Xunlei {
    private static Logger log=Logger.getLogger(Xunlei.class.getName());

    //private static volatile long fileSizeDownLoaded=0  不能保证long的原子性
    //private static long fileSizeDownLoaded=0;

    private static AtomicLong fileSizeDownLoaded=new AtomicLong(0L);  //保证原子性

    public static void main(String[] args) throws IOException, InterruptedException {
        List<Thread> list=new ArrayList<>();
        long start=System.currentTimeMillis();

        String url="http://www.hostbuf.com/downloads/finalshell_install.exe";
        //1.获取要下载的文件大小
        long fileSize=getDownLoadFileSize(url);
        log.info("待下载的文件大小"+fileSize);

        //2.新文件保存的位置
        String newFileName=genFileName(url);
        log.info("下载后新文件名为："+newFileName);
        String userhome=System.getProperty("user.home");
        String downloadPath=userhome+ File.separator+newFileName;
        log.info("下载后新文件的路径："+downloadPath);

        //3.创建此新文件
        RandomAccessFile raf=new RandomAccessFile(downloadPath,"rw");
        raf.setLength(fileSize);
        raf.close();
        log.info("空的新文件创建成功");

        //4.获取本机的核数 =》线程数
        int threadSize=Runtime.getRuntime().availableProcessors();
        log.info("线程数："+threadSize);

        //5.计算每个线程要下载的字节数
        long sizePerThread=getSizePerThread(fileSize,threadSize);
        log.info("每个线程要下载的数据量为："+sizePerThread);

        //6.循环创建线程 每个线程下载自己的部分
        for(int i=0;i<threadSize;i++){
            DownLoadedSizeNotify dlsn=new DownLoadedSizeNotify() {
                @Override
                public void notifySize(long size){
//                    fileSizeDownLoaded+=size;
//
//                    synchronized (Xunlei.class){ //Xunlei在jvm中只有一个Class对象 即只有一把锁 重量级锁方案
//                        fileSizeDownLoaded+=size;
//                        System.out.println("已下载的文件总大小"+fileSizeDownLoaded);
//                    }

                    //方案三
                    fileSizeDownLoaded.addAndGet(size);
                    System.out.println("已下载的文件总大小："+fileSizeDownLoaded.get());
                }
            };
            DownLoadTask task=new DownLoadTask(i,fileSize,threadSize,sizePerThread,url,downloadPath,dlsn);
            Thread t=new Thread(task);
            t.start();
            list.add(t);
        }
        for(Thread t:list){
            t.join();
        }

        System.out.println("主线程阻塞在此 等待子线程执行完毕");
        long end=System.currentTimeMillis();
        System.out.println("程序执行的总时长："+(end-start));

    }



    /***
     * 计算每个线程要下载的字节数
     * @param fileSize
     * @param threadSize
     * @return
     */
    private static long getSizePerThread(long fileSize,int threadSize){
        return fileSize%threadSize==0?fileSize/threadSize : fileSize/threadSize+1;
    }


    /***
     * 根据日期和时间生成新文件的文件名
     * @param url
     * @return
     */
    private static String genFileName(String url){
        Date d=new Date();
        DateFormat df=new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String prefix=df.format(d);

        //后缀名
        String suffix=url.substring(url.lastIndexOf("."));
        return prefix+suffix;

    }


    /***
     * 正式下载前 获取文件大小   "HEAD"
     * @param url
     * @return
     */
    private static long getDownLoadFileSize(String url) throws IOException{
        long fileSize=0;
        URL u=new URL(url);

        HttpURLConnection connection=(HttpURLConnection) u.openConnection();

        //设置请求头
        connection.setRequestMethod("HEAD"); //head 不下载文件内容 响应头域（文件大小）
        connection.setConnectTimeout(3000);
        connection.connect();

        fileSize=connection.getContentLength();
        log.info("文件大小："+fileSize);
        return fileSize;

    }
}

interface DownLoadedSizeNotify{

    public void notifySize(long size);
}























